Skip to content

05 配置管理与App Factory

前几篇示例中,端口号、Debug 模式、Agent 模型名等配置直接写在代码中。对于本地示例,这种方式足够简单;但在生产环境中,需要区分不同运行环境,并避免将 API Key 等敏感信息写入代码。

本篇介绍两个主题:配置管理App Factory 应用工厂模式

一、配置基础

Flask 的配置本质上就是一个字典,挂在app.config上:

python
app = Flask(__name__)

# 像字典一样操作
app.config["SECRET_KEY"] = "my-secret-key"
app.config["DEBUG"] = True

# 批量更新
app.config.update(
    DEBUG=True,
    SECRET_KEY="my-secret-key",
)

配置的 key 必须是大写,这是 Flask 的约定。小写 key 会被忽略。

1.1 常用配置项

配置项说明默认值
DEBUG是否开启调试模式False
SECRET_KEY用于签名Session等的密钥None
TESTING测试模式,异常会直接抛出False
MAX_CONTENT_LENGTH请求体最大字节数None(不限制)

Agent 项目里通常还会有一些自己的配置:

python
app.config.update(
    # Flask内置
    SECRET_KEY="your-secret-key",

    # Agent相关(自定义)
    DEFAULT_MODEL="deepseek-v4-flash",
    MAX_HISTORY=50,
    API_KEY="sk-xxxx",
)

二、从文件加载配置

将配置直接写在业务代码中不利于维护,API Key 等敏感信息也可能被提交到 Git。更常见的做法是将配置放在单独文件或环境变量中。

2.1 从Python文件加载

创建一个config.py

python
# config.py
SECRET_KEY = "my-secret-key"
DEBUG = True
DEFAULT_MODEL = "deepseek-v4-flash"
MAX_HISTORY = 50

然后在应用启动时加载:

python
app = Flask(__name__)
app.config.from_pyfile("config.py")

from_pyfile会读取 Python 文件里所有大写名称的变量。

2.2 从对象加载

也可以使用类来组织配置,并通过from_object加载:

python
# config.py
class Config:
    SECRET_KEY = "my-secret-key"
    DEFAULT_MODEL = "deepseek-v4-flash"
    MAX_HISTORY = 50

class DevelopmentConfig(Config):
    DEBUG = True

class ProductionConfig(Config):
    DEBUG = False
python
app = Flask(__name__)
app.config.from_object("config.DevelopmentConfig")

from_object只是读取对象上的属性,不会实例化类。所以这里用类属性就够了。

2.3 从环境变量加载

生产环境更适合通过环境变量传入配置,使代码中不出现密钥:

bash
# 设置环境变量(FLASK_前缀是固定的)
export FLASK_SECRET_KEY="my-secret-key"
export FLASK_DEFAULT_MODEL="deepseek-v4-flash"
export FLASK_MAX_HISTORY=50
python
app = Flask(__name__)
app.config.from_prefixed_env()

加载后,app.config["SECRET_KEY"]就是"my-secret-key",前缀FLASK_会被自动去掉。

它也支持嵌套配置,用双下划线分隔:

bash
export FLASK_DATABASE__HOST="localhost"
export FLASK_DATABASE__PORT=5432
python
app.config["DATABASE"]["HOST"]  # "localhost"
app.config["DATABASE"]["PORT"]  # 5432

2.4 从JSON/TOML文件加载

如果项目使用 JSON 或 TOML 管理配置,也可以从这些格式加载:

python
import json
import tomllib

# 从JSON加载
app.config.from_file("config.json", load=json.load)

# 从TOML加载
app.config.from_file("config.toml", load=tomllib.load, text=False)

三、多环境配置

实际项目通常至少包含开发环境和生产环境两套配置。可以使用类继承区分不同环境:

python
# config.py
class Config:
    """基础配置"""
    SECRET_KEY = "change-me-in-production"
    DEFAULT_MODEL = "deepseek-v4-flash"
    MAX_HISTORY = 50


class DevelopmentConfig(Config):
    """开发环境"""
    DEBUG = True


class ProductionConfig(Config):
    """生产环境"""
    DEBUG = False


# 配置映射,方便通过名称查找
config_map = {
    "development": DevelopmentConfig,
    "production": ProductionConfig,
}

再通过环境变量选择使用哪套配置:

python
import os
from config import config_map

env = os.environ.get("FLASK_ENV", "development")
app.config.from_object(config_map[env])
bash
# 开发环境(默认)
python app.py

# 生产环境
FLASK_ENV=production python app.py

四、App Factory模式

此前示例都直接使用app = Flask(__name__)创建应用。该方式适合小型项目,但项目规模扩大后会出现几个问题:

  1. 测试不方便:想测试不同配置,没法创建多个应用实例
  2. 循环引用:其他模块import app时容易出问题
  3. 初始化顺序:扩展和蓝图的注册逻辑散落各处

App Factory(应用工厂)模式,是将创建应用、加载配置、注册蓝图等步骤封装到一个函数中:

python
def create_app():
    app = Flask(__name__)

    # 加载配置
    app.config.from_prefixed_env()

    # 注册蓝图
    from routes.chat import chat_bp
    from routes.session import session_bp
    from routes.health import health_bp
    app.register_blueprint(chat_bp, url_prefix="/api")
    app.register_blueprint(session_bp, url_prefix="/api")
    app.register_blueprint(health_bp)

    # 注册错误处理
    from errors import register_error_handlers
    register_error_handlers(app)

    return app

启动时调用该工厂函数:

python
# app.py
if __name__ == "__main__":
    app = create_app()
    app.run()

4.1 为什么叫"工厂"

工厂函数每次调用都会返回一个新的应用实例,因此可以为不同场景创建不同配置的实例:

python
# 生产环境的实例
prod_app = create_app()

# 测试用的实例
test_app = create_app()
test_app.config["TESTING"] = True

4.2 Flask自动发现

Flask 命令行工具能自动识别名为create_appmake_app的工厂函数:

bash
# Flask会自动找到create_app
flask --app app run

# 也可以指定参数
flask --app 'app:create_app(debug=True)' run

4.3 配合扩展

在 App Factory 模式下,扩展通常先创建对象,再通过init_app绑定到具体应用:

python
# 创建扩展对象(不绑定应用)
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

def create_app():
    app = Flask(__name__)
    app.config.from_prefixed_env()

    # 绑定扩展到应用
    db.init_app(app)

    return app

这样同一个扩展对象可以绑定到不同应用实例,便于测试和多环境配置。

五、完整项目结构

结合 App Factory 和配置管理后,Agent API 项目可以采用以下结构:

my-agent-api/
├── app.py              # 工厂函数 + 启动入口
├── config.py           # 多环境配置
├── routes/
│   ├── __init__.py
│   ├── chat.py
│   ├── session.py
│   └── health.py
├── errors.py           # 错误处理
└── .env                # 环境变量(不要提交到Git)

5.1 config.py

python
# config.py
import os


class Config:
    SECRET_KEY = os.environ.get("SECRET_KEY", "dev-secret-key")
    DEFAULT_MODEL = os.environ.get("DEFAULT_MODEL", "deepseek-v4-flash")
    MAX_HISTORY = int(os.environ.get("MAX_HISTORY", 50))


class DevelopmentConfig(Config):
    DEBUG = True


class ProductionConfig(Config):
    DEBUG = False


config_map = {
    "development": DevelopmentConfig,
    "production": ProductionConfig,
}

5.2 app.py

python
# app.py
import os
from flask import Flask
from config import config_map


def create_app():
    env = os.environ.get("FLASK_ENV", "development")
    app = Flask(__name__)
    app.config.from_object(config_map[env])
    app.config.from_prefixed_env()

    # 注册蓝图
    from routes.chat import chat_bp
    from routes.session import session_bp
    from routes.health import health_bp
    app.register_blueprint(chat_bp, url_prefix="/api")
    app.register_blueprint(session_bp, url_prefix="/api")
    app.register_blueprint(health_bp)

    # 注册错误处理
    from errors import register_error_handlers
    register_error_handlers(app)

    return app


if __name__ == "__main__":
    app = create_app()
    app.run()

5.3 在蓝图中访问配置

在 Blueprint 中通常不直接引用全局app变量,可以通过 Flask 提供的current_app代理访问配置:

python
from flask import Blueprint, current_app

chat_bp = Blueprint("chat", __name__)

@chat_bp.route("/chat", methods=["POST"])
def chat():
    model = current_app.config["DEFAULT_MODEL"]
    return {"model": model}

current_app会指向当前处理请求的应用实例。注意,它只在应用上下文中可用,离开请求或应用上下文后访问会报错。

六、.env文件

开发阶段可以使用python-dotenv自动加载.env文件中的环境变量,避免每次启动终端时手动export

bash
pip install python-dotenv

创建.env文件:

FLASK_ENV=development
SECRET_KEY=dev-secret-key
DEFAULT_MODEL=deepseek-v4-flash

安装python-dotenv后,Flask 会自动读取项目根目录下的.env文件。

注意:.env文件不应提交到 Git。可以在.gitignore中加入:

.env

七、总结

本篇主要介绍 Flask 项目中与可维护性相关的两项基础能力:

  • 配置加载from_pyfile(Python文件)、from_object(类)、from_prefixed_env(环境变量)
  • 多环境:用类继承区分dev/prod,通过环境变量切换
  • App Factory:把创建应用封装到create_app()函数,方便测试和扩展
  • current_app:在蓝图中通过代理访问应用配置
  • .env文件:开发时自动加载环境变量,不要提交到Git

下一篇将介绍错误处理和日志,用于保证接口在异常情况下返回稳定响应,并为问题定位提供依据。